package com.example.customannotation.IDempotent;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * Created with IntelliJ IDEA 2023.
 * Description:
 * User: homechen
 * Date: 2024-04-24
 * Time: 20:32
 */

/**
 * 幂等性拦截器
 */
@Component
public class IdempotentInterceptor implements HandlerInterceptor {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 通过handler获取这个方法
        Method method = ((HandlerMethod) handler).getMethod();
        // 拿到这个幂等性注解
        Idempotent idempotent = method.getAnnotation(Idempotent.class);
        if (idempotent != null) {
            // 获取请求中的唯一标识符
            String requestId = obtainRequestId(request, idempotent.requestId());
            // 去redis判断这个ID是否已经请求过了
            if (redisTemplate.opsForValue().get(idempotentKey(requestId)) != null) {
                // 此时已经处理过了，返回幂等响应
                response.getWriter().write("重复请求");
                return false;
            } else {
                // 存入redis中，并设置过期时间
                redisTemplate.opsForValue().set(idempotentKey(requestId), "processed", idempotent.expireTime(), TimeUnit.SECONDS);
                return true;
            }
        }
        // 此时没有获取到幂等性注解
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    private String idempotentKey(String requestId) {
        return "idmpotent:" + requestId;
    }

    private String obtainRequestId(HttpServletRequest request, String str) {
        return request.getParameter(str);
    }
}
